/*
 * Espressif Modified MIT License
 *
 * Copyright (c) 2025 Espressif Systems (Shanghai) Co., LTD
 *
 * Permission is hereby granted for use **exclusively** with Espressif Systems products.
 * This includes the right to use, copy, modify, merge, publish, distribute, and sublicense
 * the Software, subject to the following conditions:
 *
 * 1. This Software **must be used in conjunction with Espressif Systems products**.
 * 2. The above copyright notice and this permission notice shall be included in all copies
 *    or substantial portions of the Software.
 * 3. Redistribution of the Software in source or binary form **for use with non-Espressif products**
 *    is strictly prohibited.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
 * FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * SPDX-License-Identifier: MIT-ESPRESSIF
 */

#pragma once

#include "esp_err.h"

/**
 * @brief  Chat operation modes for Coze interaction.
 */
typedef enum {
    COZE_CHAT_SPEECH_INTERRUPT_MODE = 0, /*!< This mode allows direct voice-interruptible conversation. */
    COZE_CHAT_NORMAL_MODE,               /*!< This mode is typically used for button-triggered conversations */
} coze_chat_mode_t;

typedef enum {
    COZE_CHAT_EVENT_CHAT_CREATE = 0,
    COZE_CHAT_EVENT_CHAT_UPDATE,
    COZE_CHAT_EVENT_CHAT_COMPLETED,
    COZE_CHAT_EVENT_CHAT_SPEECH_STARTED,
    COZE_CHAT_EVENT_CHAT_SPEECH_STOPED,
    COZE_CHAT_EVENT_CHAT_ERROR,
    COZE_CHAT_EVENT_INPUT_AUDIO_BUFFER_COMPLETED,
} coze_chat_event_t;

typedef enum {
    COZE_CHAT_AUDIO_TYPE_PCM = 0,
    COZE_CHAT_AUDIO_TYPE_OPUS,
    COZE_CHAT_AUDIO_TYPE_G711,
} coze_chat_audio_type_t;

typedef void *coze_chat_handle_t;
typedef void (*coze_chat_audio_callback_t)(char *data, int len, void *ctx);
typedef void (*coze_chat_event_callback_t)(coze_chat_event_t event, void *ctx);

#define COZE_CHAT_DEFAULT_CONFIG() {                       \
    .bot_id             = NULL,                            \
    .access_token       = NULL,                            \
    .user_id            = "userid_123",                    \
    .voice_id           = "7426720361733144585",           \
    .mode               = COZE_CHAT_SPEECH_INTERRUPT_MODE, \
    .audio_type         = COZE_CHAT_AUDIO_TYPE_PCM,        \
    .audio_callback_ctx = NULL,                            \
    .event_callback_ctx = NULL,                            \
    .audio_callback     = NULL,                            \
    .event_callback     = NULL,                            \
};

/**
 * @brief Configuration structure for initializing a Coze chat session.
 */
typedef struct {
    char                      *bot_id;                /*!< Bot ID assigned by Coze platform */
    char                      *access_token;          /*!< Access token for authentication */
    char                      *event_id;              /*!< Unique event ID for the current session or interaction */
    char                      *user_id;               /*!< User ID representing the client/user. see: https://www.coze.cn/open/docs/developer_guides/streaming_chat_event?from=search */
    char                      *voice_id;              /*!< Voice ID specifying the system voice to use. see: https://www.coze.cn/open/docs/guides/sys_voice */
    coze_chat_mode_t           mode;                  /*!< Chat mode: interruptible or normal */
    void                      *audio_callback_ctx;    /*!< Context pointer passed to the audio callback */
    void                      *event_callback_ctx;    /*!< Context pointer passed to the event callback */
    coze_chat_audio_type_t     audio_type;            /*!< Type of audio input/output to use */
    coze_chat_audio_callback_t audio_callback;        /*!< Callback function for handling audio data */
    coze_chat_event_callback_t event_callback;        /*!< Callback function for handling Coze events */
} coze_chat_config_t;

/**
 * @brief  Initialize the chat module.
 *
 * @param[in]  config  Pointer to the chat configuration structure.
 * @return
 */
coze_chat_handle_t coze_chat_init(coze_chat_config_t *config);

/**
 * @brief  Deinitialize the chat module.
 *
 * @param[in]  chat  Handle to the chat instance.
 * 
* @return
 *       - ESP_OK   On success
 *       - ESP_FAIL On failure
 */
esp_err_t coze_chat_deinit(coze_chat_handle_t chat);

/**
 * @brief  Start the chat session.
 *
 * @param[in]  chat  Handle to the chat instance.
 *
 * @return
 *       - ESP_OK   On success
 *       - ESP_FAIL On failure
 */
esp_err_t coze_chat_start(coze_chat_handle_t chat);

/**
 * @brief  Stop the chat session.
 *
 * @param[in]  chat  Handle to the chat instance.
 *
 * @return
 *       - ESP_OK   On success
 *       - ESP_FAIL On failure
 */
esp_err_t coze_chat_stop(coze_chat_handle_t chat);

/**
 * @brief  Send audio data to the chat session.
 *
 * @param[in]  chat  Handle to the chat instance.
 * @param[in]  data  Pointer to the audio data buffer.
 * @param[in]  len   Length of the audio data in bytes.
 *
 * @return
 *       - ESP_OK   On success
 *       - ESP_FAIL On failure
 */
esp_err_t coze_chat_send_audio_data(coze_chat_handle_t chat, char *data, int len);

/**
 * @brief  Clear the audio data buffer.
 *
 * @param[in]  chat  Handle to the chat instance.
 *
 * @return
 *       - ESP_OK   On success
 *       - ESP_FAIL On failure
 */
esp_err_t coze_chat_audio_data_clearup(coze_chat_handle_t chat);

/**
 * @brief  Indicate that the audio data transmission is complete.
 * @note: This function should be called after all audio data has been sent.
 *        This is only used when triggered by a button, and after the recording is completed and the button is released, use this API
 * 
 * @param[in]  chat  Handle to the chat instance.
 *
 * @return
 *       - ESP_OK   On success
 *       - ESP_FAIL On failure
 */
esp_err_t coze_chat_send_audio_complete(coze_chat_handle_t chat);

/**
 * @brief  Cancel the audio transmission.
 * @note: Interrupt the current conversation. When it is necessary to stop the distribution of the current server, this API can be used
 * 
 * @param[in]  chat  Handle to the chat instance.
 *
 * @return
 *       - ESP_OK   On success
 *       - ESP_FAIL On failure
 */
esp_err_t coze_chat_send_audio_cancel(coze_chat_handle_t chat);

/**
 * @brief  Update the chat session status.
 *
 * @param[in]  chat  Handle to the chat instance.
 *
 * @return
 *       - ESP_OK   On success
 *       - ESP_FAIL On failure 
 */
esp_err_t coze_chat_update_chat(coze_chat_handle_t chat);
